feat: add a keyboard shortcuts help screen - #294
Merged
Conversation
torrra had no way to discover its keybindings from inside the app. There is no footer, and ENABLE_COMMAND_PALETTE is off, so Textual's built-in palette is unavailable too. Learning that j/k navigate a list, or that p pauses a download, meant leaving the app and reading the docs. Press ? to open a modal listing every shortcut, grouped by where it applies, using the same sections as the TUI controls tables in docs/usage.md. Press ? again, or Esc, to close it. The binding is priority so that it still fires while a list has focus. That would otherwise swallow "?" while someone is typing a search query, so check_action stands the binding down whenever an Input is focused. Because a priority binding stays live while the modal is open, the action toggles rather than guards, so a second ? closes the screen instead of doing nothing. The panel is capped at 80% of the screen and scrolls with the same keys as the rest of the app rather than arrows alone: VerticalScroll ships no vim bindings, so the screen would otherwise list keys it then ignored. Closes the "Keyboard Shortcuts Overlay / Help Screen" roadmap item.
YousefHadder
force-pushed
the
feat/help-screen
branch
from
August 18, 2026 05:16
6e96d5c to
9b812f5
Compare
Owner
|
@YousefHadder LGTM! I made a few changes to the UI, though. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds a
?overlay listing every binding, grouped by where it applies, since most keys only do something in either the search results or the downloads list. Closes the "Keyboard Shortcuts Overlay / Help Screen" roadmap item.How it works
?needspriority=Trueto fire while a list has focus. But?is also an ordinary character someone might type into a search query, socheck_action()stands the binding down whenever anInputis focused. Because the binding stays live while the modal is open,action_show_help()toggles rather than guarding — a second?closes it instead of doing nothing.The panel scrolls with the same keys as the rest of the app (
j/k,ctrl+d/ctrl+u,gg/G). AVerticalScrollonly binds the arrow keys by default, which would have left this screen contradicting the vim-style keys it documents. The list already overflows a 24-row terminal today.SHORTCUTSis a plain data list, so adding a binding later is one line, and the container isheight: autowithmax-height: 80%so it grows and scrolls on its own.Rebased on #292
This is now rebased onto
mainwith #292 merged, and the overlap is resolved rather than pending.#292 restructured the TUI controls docs into the same sections this screen uses, so
docs/usage.mdneeded a real merge rather than a replay: the new rows drop into its "Anywhere in the app" table and the prose section sits alongside it, no duplicated tables. Its four new bindings are listed here too —s,S,f,x— withxdescribed as "reset to your defaults" rather than "clear filters", sinceaction_clear_filtersresets to the configureddefault_sort/default_sort_order/min_seedersbaseline, not to raw relevance.Also added a Menus section covering the theme and sort selectors, which bind identically (
j/k,enter,esc). Worth having because?is reachable from inside those menus —check_action()only stands down for anInput, and aListViewisn't one — so pressing?there now answers "what do I do here?" instead of showing a list that omits it.The pre-existing inaccuracies I'd left alone (
randqdon't exist,d/Dundocumented,Enteropens a details panel first) were fixed by #292's rewrite, so they're gone from the merged docs.Note for #293
#293 still overlaps in
docs/usage.mdandsrc/torrra/app.py. Theapp.pyone is just two adjacent imports; the methods on both sides coexist fine.Worth a look when it lands: it binds
fon the downloads view (open file manager) while #292 bindsfon the search view (toggle seeded-only). Those can't collide at runtime — they're on opposite sides of theContentSwitcher, so only one is ever in the focus chain — but the flat tables inusage.mdwill end up listingftwice with contradictory descriptions unless the rows are scoped. This screen's sections are context-scoped, so it represents that distinction correctly. Happy to add itsspace/enter/left/rightrows once it merges.Testing
13 unit tests plus a snapshot; full suite is 163 passed, 5 snapshots. Docs build clean under
sphinx-build -W.The unit tests assert content, not layout — which is exactly how an earlier
min-widthlet rows wrap and pushed the bottom two sections out of view while everything stayed green. The snapshot covers that. It's deliberately sized 90x50, larger than its siblings: the full list is now 40 rows and the panel is capped at 80% of the screen, so anything shorter clips the bottom sections and the snapshot would never catch a regression down there. Adding the #292 rows tripped exactly that — the old 90x40 size started cutting off Downloads and Menus — so there's a comment on the test to grow it ifSHORTCUTSgrows.Known limitation
?doesn't open help on the welcome screen. Its only focusable widget is the search input, socheck_action()always suppresses the binding and the?goes into the query box instead. Help works everywhere once you've searched. Fixable, but the fix means special-casing an empty input, so I'd rather do it separately if we want it.